home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / cpp.arc / CPP3.C < prev    next >
C/C++ Source or Header  |  1985-12-03  |  21KB  |  612 lines

  1.  
  2. /*
  3.  *                              C P P 3 . C
  4.  *
  5.  *                  File open and command line options
  6.  *
  7.  * Edit history
  8.  * 13-Nov-84    MM      Split from cpp1.c
  9.  * 29-Apr-85    MM      Make -N work again.
  10.  * 03-Oct-85    CG      Change default loc. of <files> for P/OS.
  11.  * 08-Nov-85    ado     Prevent wierd -D arguments
  12.  */
  13.  
  14. #include        <stdio.h>
  15. #include        <ctype.h>
  16. #include        "cppdef.h"
  17. #include        "cpp.h"
  18. #if DEBUG && (HOST == SYS_VMS || HOST == SYS_UNIX)
  19. #include        <signal.h>
  20. extern int      abort();                /* For debugging                */
  21. #endif
  22.  
  23. int
  24. openfile(filename)
  25. char            *filename;
  26. /*
  27.  * Open a file, add it to the linked list of open files.
  28.  * This is called only from openfile() above.
  29.  */
  30. {
  31.         register FILE           *fp;
  32.  
  33.         if ((fp = fopen(filename, "r")) == NULL) {
  34. #if DEBUG
  35.             perror(filename);
  36. #endif
  37.             return (FALSE);
  38.         }
  39. #if DEBUG
  40.         if (debug)
  41.             fprintf(stderr, "Reading from \"%s\"\n", filename);
  42. #endif
  43.         addfile(fp, filename);
  44.         return (TRUE);
  45. }
  46.  
  47. addfile(fp, filename)
  48. FILE            *fp;                    /* Open file pointer            */
  49. char            *filename;              /* Name of the file             */
  50. /*
  51.  * Initialize tables for this open file.  This is called from openfile()
  52.  * above (for #include files), and from the entry to cpp to open the main
  53.  * input file.  It calls a common routine, getfile() to build the FILEINFO
  54.  * structure which is used to read characters.  (getfile() is also called
  55.  * to setup a macro replacement.)
  56.  */
  57. {
  58.         register FILEINFO       *file;
  59.         extern FILEINFO         *getfile();
  60.  
  61.         file = getfile(NBUFF, filename);
  62.         file->fp = fp;                  /* Better remember FILE *       */
  63.         file->buffer[0] = EOS;          /* Initialize for first read    */
  64.         line = 1;                       /* Working on line 1 now        */
  65.         wrongline = TRUE;               /* Force out initial #line      */
  66. }
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75. setincdirs()
  76. /*
  77.  * Append system-specific directories to the include directory list.
  78.  * Called only when cpp is started.
  79.  */
  80. {
  81.  
  82. #ifdef  CPP_INCLUDE
  83.         *incend++ = CPP_INCLUDE;
  84. #define IS_INCLUDE      1
  85. #else
  86. #define IS_INCLUDE      0
  87. #endif
  88.  
  89. #if HOST == SYS_UNIX
  90.         *incend++ = "/usr/include";
  91. #define MAXINCLUDE      (NINCLUDE - 1 - IS_INCLUDE)
  92. #endif
  93.  
  94. #if HOST == SYS_VMS
  95.         extern char     *getenv();
  96.  
  97.         if (getenv("C$LIBRARY") != NULL)
  98.             *incend++ = "C$LIBRARY:";
  99.         *incend++ = "SYS$LIBRARY:";
  100. #define MAXINCLUDE      (NINCLUDE - 2 - IS_INCLUDE)
  101. #endif
  102.  
  103. #if HOST == SYS_RSX
  104.         extern int      $$rsts;                 /* TRUE on RSTS/E       */
  105.         extern int      $$pos;                  /* TRUE on PRO-350 P/OS */
  106.         extern int      $$vms;                  /* TRUE on VMS compat.  */
  107.  
  108.         if ($$pos) {                            /* P/OS?                */
  109.             *incend++ = "LB:[ZZDECUSC]";        /* C #includes          */
  110.             *incend++ = "LB:[1,5]";             /* RSX library          */
  111.         }
  112.         else if ($$rsts) {                      /* RSTS/E?              */
  113.             *incend++ = "SY:@";                 /* User-defined account */
  114.             *incend++ = "C:";                   /* Decus-C library      */
  115.             *incend++ = "LB:[1,1]";             /* RSX library          */
  116.         }
  117.         else if ($$vms) {                       /* VMS compatibility?   */
  118.             *incend++ = "C:";
  119.         }
  120.         else {                                  /* Plain old RSX/IAS    */
  121.             *incend++ = "LB:[1,1]";
  122.         }
  123. #define MAXINCLUDE      (NINCLUDE - 3 - IS_INCLUDE)
  124. #endif
  125.  
  126. #if HOST == SYS_RT11
  127.         extern int      $$rsts;                 /* RSTS/E emulation?    */
  128.  
  129.         if ($$rsts)
  130.             *incend++ = "SY:@";                 /* User-defined account */
  131.         *incend++ = "C:";                       /* Decus-C library disk */
  132.         *incend++ = "SY:";                      /* System (boot) disk   */
  133. #define MAXINCLUDE      (NINCLUDE - 3 - IS_INCLUDE)
  134. #endif
  135.  
  136. #if HOST == SYS_MSDOS
  137.     {
  138.         static char incdir[ 100 ];
  139.         char *getenv();
  140.         char *foo;
  141.  
  142.         foo = getenv( "INCLUDE" );
  143.         if ( foo == NULL )
  144.         strcpy( incdir, "\\include\\" );
  145.         else {
  146.         strncpy( incdir, foo, 99 );
  147.          incdir[ 98 ] = EOS;
  148.         strcat( incdir, "\\" );
  149.         *incend++ = incdir;
  150.         } /* End if */
  151.     } /* End hack */
  152. #define    MAXINCLUDE    (NINCLUDE - 1 - IS_INCLUDE)
  153. #endif
  154. }
  155.  
  156.  
  157.  
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164.  
  165.  
  166. int
  167. dooptions(argc, argv)
  168. int             argc;
  169. char            *argv[];
  170. /*
  171.  * dooptions is called to process command line arguments (-Detc).
  172.  * It is called only at cpp startup.
  173.  */
  174. {
  175.         register char           *ap;
  176.         register DEFBUF         *dp;
  177.         register int            c;
  178.         int                     i, j;
  179.         char                    *arg;
  180.         SIZES                   *sizp;          /* For -S               */
  181.         int                     size;           /* For -S               */
  182.         int                     isdatum;        /* FALSE for -S*        */
  183.         int                     endtest;        /* For -S               */
  184.         char                    *cp;            /* For -D arg test      */
  185.  
  186.         for (i = j = 1; i < argc; i++) {
  187.             arg = ap = argv[i];
  188.             if (*ap++ != '-' || *ap == EOS)
  189.                 argv[j++] = argv[i];
  190.             else {
  191.                 c = *ap++;                      /* Option byte          */
  192.                 if (islower(c))                 /* Normalize case       */
  193.                     c = toupper(c);
  194.                 switch (c) {                    /* Command character    */
  195.                 case 'C':                       /* Keep comments        */
  196.                     cflag = TRUE;
  197.                     keepcomments = TRUE;
  198.                     break;
  199.  
  200.                 case 'D':                       /* Define symbol        */
  201.                     /*
  202.                      * Check for incorrect argument -- don't allow
  203.                      * -Dfoo(bar)=something
  204.                      */
  205.                     if (type[*ap] != LET)
  206.                         cfatal("Argument needed for -D in \"%s\"", arg);
  207.                     for (cp = ap; *cp != EOS && *cp != '='; cp++) {
  208.                         if (type[*cp] != LET && type[*cp] != DIG)
  209.                             cfatal("Incorrect argument for -D in \"%s\"", arg);
  210.                     }
  211. #if HOST != SYS_UNIX         && HOST != SYS_MSDOS
  212.                     zap_uc(ap);                 /* Force define to U.C. */
  213. #endif
  214. #if OK_TRIGRAPH
  215.                     if (tflag)
  216.                         trigraph(ap);
  217. #endif
  218.                     /*
  219.                      * If the option is just "-Dfoo", make it -Dfoo=1
  220.                      */
  221.                     while (*ap != EOS && *ap != '=')
  222.                         ap++;
  223.                     if (*ap == EOS)
  224.                         ap = "1";
  225.                     else
  226.                         *ap++ = EOS;
  227.                     /*
  228.                      * Now, save the word and its definition.
  229.                      */
  230.                     dp = defendel(argv[i] + 2, FALSE);
  231.                     dp->repl = savestring(ap);
  232.                     dp->nargs = DEF_NOARGS;
  233.                     break;
  234.  
  235.                 case 'E':                       /* Ignore non-fatal     */
  236.                     eflag = TRUE;               /* errors.              */
  237.                     break;
  238.  
  239.                 case 'I':                       /* Include directory    */
  240.                     if (incend >= &incdir[MAXINCLUDE])
  241.                         cfatal("Too many include directories", NULLST);
  242.                     *incend++ = ap;
  243.                     break;
  244.  
  245.                 case 'N':                       /* No predefineds       */
  246.                     /*
  247.                      * cpp -n           remove "vax" and friends.
  248.                      * cpp -n -n        remove __LINE__, too.
  249.                      */
  250.                     nflag++;
  251.                     unpredefine();
  252.                     break;
  253.  
  254.                 case 'P':                       /* no #line output      */
  255.                     pflag = TRUE;
  256.                     break;
  257.  
  258.                 case 'S':
  259.                     sizp = size_table;
  260.                     if (isdatum = (*ap != '*')) /* If it's just -S,     */
  261.                         endtest = T_FPTR;       /* Stop here            */
  262.                     else {                      /* But if it's -S*      */
  263.                         ap++;                   /* Step over '*'        */
  264.                         endtest = 0;            /* Stop at end marker   */
  265.                     }
  266.                     while (sizp->bits != endtest && *ap != EOS) {
  267.                         if (!isdigit(*ap)) {    /* Skip to next digit   */
  268.                             ap++;
  269.                             continue;
  270.                         }
  271.                         size = 0;               /* Compile the value    */
  272.                         while (isdigit(*ap)) {
  273.                             size *= 10;
  274.                             size += (*ap++ - '0');
  275.                         }
  276.                         if (isdatum)
  277.                             sizp->size = size;  /* Datum size           */
  278.                         else
  279.                             sizp->psize = size; /* Pointer size         */
  280.                         sizp++;
  281.                     }
  282.                     if (sizp->bits != endtest)
  283.                         cwarn("-S, too few values specified in %s", argv[i]);
  284.                     else if (*ap != EOS)
  285.                         cwarn("-S, too many values, \"%s\" unused", ap);
  286.                     break;
  287.  
  288. #if    HOST == SYS_MSDOS
  289.                 /* Support the selection of different
  290.                 ** memory models for the iAPX86 family
  291.                 */
  292.                 case 'M':
  293.             sizp = size_table;    /* Get start of table...    */
  294.             switch( *ap )
  295.             {
  296.                 /* s, m and l models work with MicroSoft C
  297.                 **        Version 3.00 and above.
  298.                 **
  299.                 ** s, p, d and l work with Lattice C
  300.                 **        Version 2.0 and above.
  301.                 */
  302.  
  303.             case 's' :    /* Small Model...        */
  304.             case 'p' :    /* Large Code, Small Data...    */
  305.                 ms_dos_model = *ap;
  306.                         while ( sizp -> bits )
  307.                 ( sizp++ ) -> psize = 2;
  308.                 break;
  309.  
  310.             case 'd' :    /* Small code, large data...    */
  311.             case 'l' :    /* Large model...        */
  312.                 ms_dos_model = *ap;
  313.                 while ( sizp -> bits )
  314.                 ( sizp++ ) -> psize = 4;
  315.                 break;
  316.  
  317.             case 'm' :    /* Large code, small data...    */
  318.                 ms_dos_model = *ap;
  319.                 while ( sizp -> bits != T_FPTR )
  320.                 ( sizp++ ) -> psize = 2;
  321.                     /* All data pointers are short.    */
  322.                 sizp -> psize = 4;
  323.                     /* Function pointers are long.    */
  324.  
  325.                 break;
  326.  
  327.             default :    /* Invalid model?        */
  328.                 cwarn("-M, invalid memory model '%c'", *ap);
  329.             } /* End switch */
  330.         break;
  331. #endif /* "-M" option support */
  332.  
  333.                 case 'T':
  334.                     if (isdigit(*ap))
  335.                         tflag = atoi(ap);
  336.                     else {
  337.                         tflag = !tflag;
  338.                         fprintf(stderr, "Trigraph recognition %sabled\n",
  339.                             (tflag) ? "en" : "dis");
  340.                     }
  341.                     break;
  342.  
  343.                 case 'U':                       /* Undefine symbol      */
  344. #if HOST != SYS_UNIX        && HOST != SYS_MSDOS
  345.                     zap_uc(ap);
  346. #endif
  347.                     /*
  348.                      * We don't need to map trigraphs as they
  349.                      * can't be part of a symbol name.
  350.                      * (_ isn't trigraphable).
  351.                      */
  352.                     if (defendel(ap, TRUE) == NULL)
  353.                         cwarn("\"%s\" wasn't defined", ap);
  354.                     break;
  355.  
  356. #if DEBUG
  357.                 case 'X':                       /* Debug                */
  358.                     debug = (isdigit(*ap)) ? atoi(ap) : 1;
  359. #if (HOST == SYS_VMS || HOST == SYS_UNIX)
  360.                     signal(SIGINT, abort);      /* Trap "interrupt"     */
  361. #endif
  362.                     fprintf(stderr, "Debug set to %d\n", debug);
  363.                     break;
  364. #endif
  365.  
  366.                 default:                        /* What is this one?    */
  367.                     cwarn("Unknown option \"%s\"", arg);
  368.                     fprintf(stderr, "The following options are valid:\n\
  369.   -C\t\t\tWrite source file comments to output\n\
  370.   -Dsymbol=value\tDefine a symbol with the given (optional) value\n\
  371.   -Idirectory\t\tAdd a directory to the #include search list\n\
  372.   -N\t\t\tDon't predefine target-specific names\n\
  373.   -P\t\t\tDon't output #line lines\n\
  374.   -Stext\t\tSpecify sizes for #if sizeof\n\
  375.   -Usymbol\t\tUndefine symbol\n");
  376. #if DEBUG
  377.                     fprintf(stderr, "  -Xvalue\t\tSet internal debug flag\n");
  378. #endif
  379.                     break;
  380.                 }                       /* Switch on all options        */
  381.             }                           /* If it's a -option            */
  382.         }                               /* For all arguments            */
  383.         if (j > 3) {
  384.             cerror(
  385.                 "Too many file arguments.  Usage: cpp [input [output]]",
  386.                 NULLST);
  387.         }
  388.         return (j);                     /* Return new argc              */
  389. }
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403. #if HOST != SYS_UNIX        && HOST != SYS_MSDOS
  404. FILE_LOCAL
  405. zap_uc(ap)
  406. register char   *ap;
  407. /*
  408.  * Dec operating systems mangle upper-lower case in command lines.
  409.  * This routine forces the -D and -U arguments to uppercase.
  410.  * It is called only on cpp startup by dooptions().
  411.  */
  412. {
  413.         while (*ap != EOS) {
  414.             /*
  415.              * Don't use islower() here so it works with Multinational
  416.              */
  417.             if (*ap >= 'a' && *ap <= 'z')
  418.                 *ap = toupper(*ap);
  419.             ap++;
  420.         }
  421. }
  422. #endif
  423.  
  424. initdefines()
  425. /*
  426.  * Initialize the built-in #define's.  There are two flavors:
  427.  *      #define decus   1               (static definitions)
  428.  *      #define __FILE__ ??             (dynamic, evaluated by magic)
  429.  * Called only on cpp startup.
  430.  *
  431.  * Note: the built-in static definitions are supressed by the -N option.
  432.  * __LINE__, __FILE__, and __DATE__ are always present.
  433.  */
  434. {
  435.         register char           **pp;
  436.         register char           *tp;
  437.         register DEFBUF         *dp;
  438.         int                     i;
  439.         long                    tvec;
  440.         extern char             *ctime();
  441.  
  442.         /*
  443.          * Predefine the built-in symbols.  Allow the
  444.          * implementor to pre-define a symbol as "" to
  445.          * eliminate it.
  446.          */
  447.         if (nflag == 0) {
  448.             for (pp = preset; *pp != NULL; pp++) {
  449.                 if (*pp[0] != EOS) {
  450.                     dp = defendel(*pp, FALSE);
  451.                     dp->repl = savestring("1");
  452.                     dp->nargs = DEF_NOARGS;
  453.                 }
  454.             }
  455.         }
  456.         /*
  457.          * The magic pre-defines (__FILE__ and __LINE__ are
  458.          * initialized with negative argument counts.  expand()
  459.          * notices this and calls the appropriate routine.
  460.          * DEF_NOARGS is one greater than the first "magic" definition.
  461.          */
  462.         if (nflag < 2) {
  463.             for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) {
  464.                 dp = defendel(*pp, FALSE);
  465.                 dp->nargs = --i;
  466.             }
  467. #if OK_DATE
  468.             /*
  469.              * Define __DATE__ as today's date.
  470.              */
  471.             dp = defendel("__DATE__", FALSE);
  472.             dp->repl = tp = getmem(27);
  473.             dp->nargs = DEF_NOARGS;
  474.             time(&tvec);
  475.             *tp++ = '"';
  476.             strcpy(tp, ctime(&tvec));
  477.             tp[24] = '"';                       /* Overwrite newline    */
  478. #endif
  479.         }
  480. }
  481.  
  482. FILE_LOCAL
  483. unpredefine()
  484. /*
  485.  * Remove predefined symbols from the symbol table.
  486.  * The strange ordering (insert, command-line-scan, remove)
  487.  * is needed to avoid interaction with user-specified -D arguments.
  488.  */
  489. {
  490.         register char           **pp;
  491.  
  492.         for (pp = preset; *pp != NULL; pp++) {
  493.             if (*pp[0] != EOS)
  494.                 defendel(*pp, TRUE);
  495.         }
  496.         if (nflag > 1) {
  497.             for (pp = magic; *pp != NULL; pp++)
  498.                 defendel(*pp, TRUE);
  499. #if OK_DATE
  500.             defendel("__DATE__", TRUE);
  501. #endif
  502.         }
  503. }
  504.  
  505.  
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512.  
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523. #if HOST == SYS_VMS
  524. /*
  525.  * getredirection() is intended to aid in porting C programs
  526.  * to VMS (Vax-11 C) which does not support '>' and '<'
  527.  * I/O redirection.  With suitable modification, it may
  528.  * useful for other portability problems as well.
  529.  */
  530.  
  531. int
  532. getredirection(argc, argv)
  533. int             argc;
  534. char            **argv;
  535. /*
  536.  * Process vms redirection arg's.  Exit if any error is seen.
  537.  * If getredirection() processes an argument, it is erased
  538.  * from the vector.  getredirection() returns a new argc value.
  539.  *
  540.  * Warning: do not try to simplify the code for vms.  The code
  541.  * presupposes that getredirection() is called before any data is
  542.  * read from stdin or written to stdout.
  543.  *
  544.  * Normal usage is as follows:
  545.  *
  546.  *      main(argc, argv)
  547.  *      int             argc;
  548.  *      char            *argv[];
  549.  *      {
  550.  *              argc = getredirection(argc, argv);
  551.  *      }
  552.  */
  553. {
  554.         register char           *ap;    /* Argument pointer     */
  555.         int                     i;      /* argv[] index         */
  556.         int                     j;      /* Output index         */
  557.         int                     file;   /* File_descriptor      */
  558.  
  559.         for (j = i = 1; i < argc; i++) {   /* Do all arguments  */
  560.             switch (*(ap = argv[i])) {
  561.             case '<':                   /* <file                */
  562.                 if (freopen(++ap, "r", stdin) == NULL) {
  563.                     perror(ap);         /* Can't find file      */
  564.                     exit(IO_ERROR);     /* Is a fatal error     */
  565.                 }
  566.                 break;
  567.  
  568.             case '>':                   /* >file or >>file      */
  569.                 if (*++ap == '>') {     /* >>file               */
  570.                     /*
  571.                      * If the file exists, and is writable by us,
  572.                      * call freopen to append to the file (using the
  573.                      * file's current attributes).  Otherwise, create
  574.                      * a new file with "vanilla" attributes as if the
  575.                      * argument was given as ">filename".
  576.                      * access(name, 2) returns zero if we can write on
  577.                      * the specified file.
  578.                      */
  579.                     if (access(++ap, 2) == 0) {
  580.                         if (freopen(ap, "a", stdout) != NULL)
  581.                             break;      /* Exit case statement  */
  582.                         perror(ap);     /* Error, can't append  */
  583.                         exit(IO_ERROR); /* After access test    */
  584.                     }                   /* If file accessable   */
  585.                 }
  586.                 /*
  587.                  * On vms, we want to create the file using "standard"
  588.                  * record attributes.  creat(...) creates the file
  589.                  * using the caller's default protection mask and
  590.                  * "variable length, implied carriage return"
  591.                  * attributes. dup2() associates the file with stdout.
  592.                  */
  593.                 if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1
  594.                  || dup2(file, fileno(stdout)) == -1) {
  595.                     perror(ap);         /* Can't create file    */
  596.                     exit(IO_ERROR);     /* is a fatal error     */
  597.                 }                       /* If '>' creation      */
  598.                 break;                  /* Exit case test       */
  599.  
  600.             default:
  601.                 argv[j++] = ap;         /* Not a redirector     */
  602.                 break;                  /* Exit case test       */
  603.             }
  604.         }                               /* For all arguments    */
  605.         argv[j] = NULL;                 /* Terminate argv[]     */
  606.         return (j);                     /* Return new argc      */
  607. }
  608. #endif
  609.  
  610.  
  611.  
  612.